﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using OpenGLES;
class Glu
{
    /*
  ** Make m an identity matrix
  */
    static void _gluMakeIdentityd(ref float[] m)
    {
        m[0] = 1; m[4] = 0; m[8] = 0; m[12] = 0;
        m[1] = 0; m[5] = 1; m[9] = 0; m[13] = 0;
        m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0;
        m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1;
    }

    static void __gluMultMatrixVecd(ref float[] matrix, ref float[] _in, ref float[] _out)
    {
        int i;
        for (i = 0; i < 4; i++)
        {
            _out[i] =
            _in[0] * matrix[0 * 4 + i] +
            _in[1] * matrix[1 * 4 + i] +
            _in[2] * matrix[2 * 4 + i] +
            _in[3] * matrix[3 * 4 + i];
        }
    }

    static void __gluMultMatricesd(ref float[] a, ref float[] b,
                ref float[] r)
    {
        int i, j;
        for (i = 0; i < 4; i++)
        {
            for (j = 0; j < 4; j++)
            {
                r[i * 4 + j] =
                a[i * 4 + 0] * b[0 * 4 + j] +
                a[i * 4 + 1] * b[1 * 4 + j] +
                a[i * 4 + 2] * b[2 * 4 + j] +
                a[i * 4 + 3] * b[3 * 4 + j];
            }
        }
    }

    /*
** inverse = invert(src)
*/
    bool __gluInvertMatrixd(ref float[] src)
    {
        int i, j, k, swap;
        float t;
        float[] inverse = new float[16];
        float[][] temp = new float[4][];
        temp[0] = new float[4];
        temp[1] = new float[4];
        temp[2] = new float[4];
        temp[3] = new float[4];

        for (i = 0; i < 4; i++)
        {
            for (j = 0; j < 4; j++)
            {
                temp[i][j] = src[i * 4 + j];
            }
        }
        _gluMakeIdentityd(ref inverse);
        for (i = 0; i < 4; i++)
        {
            /*
            ** Look for largest element in column
            */
            swap = i;
            for (j = i + 1; j < 4; j++)
            {

                if (Math.Abs(temp[j][i]) > Math.Abs(temp[i][i]))
                {
                    swap = j;
                }
            }

            if (swap != i)
            {
                /*
                ** Swap rows.
                */
                for (k = 0; k < 4; k++)
                {
                    t = temp[i][k];
                    temp[i][k] = temp[swap][k];
                    temp[swap][k] = t;

                    t = inverse[i * 4 + k];
                    inverse[i * 4 + k] = inverse[swap * 4 + k];
                    inverse[swap * 4 + k] = t;
                }
            }

            if (temp[i][i] != 0)
            {
                /*
                ** No non-zero pivot.  The matrix is singular, which shouldn't
                ** happen.  This means the user gave us a bad matrix.
                */
                //return false;
            }

            t = temp[i][i];
            for (k = 0; k < 4; k++)
            {
                temp[i][k] /= t;
                inverse[i * 4 + k] /= t;
            }
            for (j = 0; j < 4; j++)
            {
                if (j != i)
                {
                    t = temp[j][i];
                    for (k = 0; k < 4; k++)
                    {
                        temp[j][k] -= temp[i][k] * t;
                        inverse[j * 4 + k] -= inverse[i * 4 + k] * t;
                    }
                }
            }
        }
        return true;
    }



    void gluUnProject(float winx, float winy, float winz,
        float[] modelMatrix, float[] projMatrix,
         int[] viewport, out float objx, out float objy, out float objz)
    {
        float[] finalMatrix = new float[16];
        float[] _in = new float[4];
        float[] _out = new float[4];

        __gluMultMatricesd(ref modelMatrix, ref projMatrix, ref finalMatrix);
        //if (!__gluInvertMatrixd(ref finalMatrix, ref finalMatrix)) return(false);
        __gluInvertMatrixd(ref finalMatrix);
        _in[0] = winx;
        _in[1] = winy;
        _in[2] = winz;
        _in[3] = 1.0f;

        /* Map x and y from window coordinates */
        _in[0] = (_in[0] - viewport[0]) / viewport[2];
        _in[1] = (_in[1] - viewport[1]) / viewport[3];

        /* Map to range -1 to 1 */
        _in[0] = _in[0] * 2 - 1;
        _in[1] = _in[1] * 2 - 1;
        _in[2] = _in[2] * 2 - 1;

        __gluMultMatrixVecd(ref finalMatrix, ref _in, ref _out);
        _out[0] /= _out[3];
        _out[1] /= _out[3];
        _out[2] /= _out[3];
        objx = _out[0];
        objy = _out[1];
        objz = _out[2];
    }
    public unsafe Coordenada coordenadasXY1(int xVentana, int yVentana)
    {
        int[] _viewport = new int[4];
        float[] _modelview = new float[16];
        float[] _projection = new float[16];
        fixed (int* viewport = &_viewport[0])
        {
            fixed (float* modelview = &_modelview[0], projection = &_projection[0])
            {
                float winX = 0;
                float winY = 0;
                float winZ = 0;
                float posX = 0;
                float posY = 0;
                float posZ = 0;
                GL.GetFloatv(GL.GL_MODELVIEW_MATRIX, modelview);
                GL.GetFloatv(GL.GL_PROJECTION_MATRIX, projection);
                GL.GetIntegerv(GL.GL_VIEWPORT, viewport);
                winX = xVentana;
                winY = viewport[3] - yVentana;
                //Gl.glReadPixels(xVentana, Integer.Parse(winY), 1, 1, Gl.GL_DEPTH_COMPONENT, Gl.GL_FLOAT, winZ)
                gluUnProject(winX, winY, winZ, _modelview, _projection, _viewport, out posX, out posY, out posZ);
                //Gl.glRotatef(intRotacion, 0.0F, 0.0F, 1.0F)
                posX -= 0.5f;
                posX *= 100f;
                posY -= 0.5f;
                posY *= 100f;
                return new Coordenada(posX, posY);
            }
        }
    }
}
